package com.xbongbong.saas.model.impl;

import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.domain.dao.ProductSerialBalanceDao;
import com.xbongbong.saas.domain.entity.ContractProductEntity;
import com.xbongbong.saas.domain.entity.InstockProductEntity;
import com.xbongbong.saas.domain.entity.OutstockProductEntity;
import com.xbongbong.saas.domain.entity.ProductSerialBalanceEntity;
import com.xbongbong.saas.domain.entity.ProductSerialFlowEntity;
import com.xbongbong.saas.domain.entity.ReturnedPurchaseProductEntity;
import com.xbongbong.saas.domain.entity.TransferProductEntity;
import com.xbongbong.saas.domain.entity.WarehouseOristockProductEntity;
import com.xbongbong.saas.domain.entity.ext.InstockEntityExt;
import com.xbongbong.saas.domain.entity.ext.ProductEntityExt;
import com.xbongbong.saas.domain.entity.ext.RefundEntityExt;
import com.xbongbong.saas.enums.InstockTypeEnum;
import com.xbongbong.saas.enums.OutstockTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.InstockEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.enums.business.RefundEnum;
import com.xbongbong.saas.model.ContractProductModel;
import com.xbongbong.saas.model.InstockModel;
import com.xbongbong.saas.model.InstockProductModel;
import com.xbongbong.saas.model.OutstockProductModel;
import com.xbongbong.saas.model.ProductModel;
import com.xbongbong.saas.model.ProductSerialBalanceModel;
import com.xbongbong.saas.model.ProductSerialFlowModel;
import com.xbongbong.saas.model.RefundModel;
import com.xbongbong.saas.model.ReturnedPurchaseProductModel;
import com.xbongbong.saas.model.TransferProductModel;
import com.xbongbong.saas.model.WarehouseOristockProductModel;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author jiantao.xiong
 * @date 2020/5/19
 */
@Service("productSerialBalanceModel")
public class ProductSerialBalanceModelImpl implements ProductSerialBalanceModel {

    @Resource
    private ProductSerialBalanceDao productSerialBalanceDao;
    @Resource
    private ProductSerialBalanceModel productSerialBalanceModel;
    @Resource
    private InstockModel instockModel;
    @Resource
    private ProductSerialFlowModel productSerialFlowModel;
    @Resource
    private ProductModel productModel;
    @Resource
    private WarehouseOristockProductModel warehouseOristockProductModel;
    @Resource
    private RefundModel refundModel;
    @Resource
    private ContractProductModel contractProductModel;
    @Resource
    private ReturnedPurchaseProductModel returnedPurchaseProductModel;
    @Resource
    private TransferProductModel transferProductModel;
    @Resource
    private InstockProductModel instockProductModel;
    @Resource
    private OutstockProductModel outstockProductModel;

    @Override
    public Integer insert(ProductSerialBalanceEntity entity) throws XbbException {
        long now = DateUtil.getInt();
        entity.setUpdateTime(now);
        entity.setAddTime(now);
        entity.setDate(now);
        return productSerialBalanceDao.insert(entity);
    }

    @Override
    public Integer update(ProductSerialBalanceEntity entity) throws XbbException {
        long now = DateUtil.getInt();
        entity.setUpdateTime(now);
        return productSerialBalanceDao.update(entity);
    }

    @Override
    public List<ProductSerialBalanceEntity> findEntitys(Map<String, Object> param) {
        return productSerialBalanceDao.findEntitys(param);
    }

    @Override
    public Integer getEntitysCount(Map<String, Object> param) {
        return productSerialBalanceDao.getEntitysCount(param);
    }

    @Override
    public List findEntitysWithoutSub(Map<String, Object> param) {
        return null;
    }

    @Override
    public void insertBatch(List<ProductSerialBalanceEntity> productSerialBalanceList) {
        long now = DateTimeUtil.getInt();
        for (ProductSerialBalanceEntity entity : productSerialBalanceList) {
            entity.setAddTime(now);
            entity.setUpdateTime(now);
        }
        productSerialBalanceDao.insertBatch(productSerialBalanceList);
    }

    @Override
    public Integer updateBatch(List<ProductSerialBalanceEntity> entitys, String corpid) {
        if (CollectionUtils.isEmpty(entitys)) {
            return 0;
        }
        long now = DateTimeUtil.getInt();
        for (ProductSerialBalanceEntity entity : entitys) {
            entity.setUpdateTime(now);
        }
        return productSerialBalanceDao.updateBatch(entitys, corpid);
    }

    @Override
    public void deleteSerial(String corpid, List<Long> refIdIn, Integer businessType) throws XbbException {
        List<Long> delProductIdList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (Objects.equals(businessType, XbbRefTypeEnum.ORI_STOCK.getCode())) {
            List<WarehouseOristockProductEntity> warehouseOristockProductEntities = warehouseOristockProductModel.getProductsByOriStockIdIn(corpid, refIdIn);
            warehouseOristockProductEntities.forEach(item -> delProductIdList.add(item.getProductId()));
        } else if (Objects.equals(businessType, XbbRefTypeEnum.REFUND.getCode())) {
            Map<String, Object> param = new HashMap<>();
            param.put("idIn", refIdIn);
            param.put(ParameterConstant.CORPID, corpid);
            List<RefundEntityExt> refundEntityExts = refundModel.findEntitys(param);
            List<Long> redContractIds = new ArrayList<>();
            refundEntityExts.forEach(refundEntityExt -> {
                if (Objects.nonNull(refundEntityExt.getData())) {
                    redContractIds.add(refundEntityExt.getData().getLongValue(RefundEnum.RED_CONTRACT_ID.getAttr()));
                }
            });
            List<ContractProductEntity> contractProductEntities = contractProductModel.getContractProductByContractIdIn(corpid, redContractIds);
            contractProductEntities.forEach(item -> delProductIdList.add(item.getProductId()));
        } else if (Objects.equals(businessType, XbbRefTypeEnum.RETURNED_PURCHASE.getCode())) {
            List<ReturnedPurchaseProductEntity> returnedPurchaseProductEntities = returnedPurchaseProductModel.getReturnedPurchaseProductByReturnedPurchaseIdIn(corpid, refIdIn);
            returnedPurchaseProductEntities.forEach(item -> delProductIdList.add(item.getProductId()));
        } else if (Objects.equals(businessType, XbbRefTypeEnum.TRANSFER.getCode())) {
            List<TransferProductEntity> transferProductEntities = transferProductModel.getProductsByTransferIdIn(corpid, refIdIn);
            transferProductEntities.forEach(item -> delProductIdList.add(item.getProductId()));
        } else if (InstockTypeEnum.getStockTypeMap().containsKey(businessType)) {
            List<InstockProductEntity> instockProductEntities = instockProductModel.getProductsByInstockIdIn(corpid, refIdIn);
            instockProductEntities.forEach(item -> delProductIdList.add(item.getProductId()));
        } else if (OutstockTypeEnum.getStockTypeMap().containsKey(businessType)) {
            List<OutstockProductEntity> outstockProductEntities = outstockProductModel.getProductsByOutstockIdIn(corpid, refIdIn);
            outstockProductEntities.forEach(item -> delProductIdList.add(item.getProductId()));
        }
        // 产品信息
        List<ProductEntityExt> productEntityExts = productModel.getProductListByIdIn(corpid, delProductIdList, DelEnum.NORMAL.getDel());
        List<Long> enableSerialProductIds = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (ProductEntityExt productEntityExt : productEntityExts) {
            JSONObject productData = productEntityExt.getData();
            int enableSerialNumber = productData.getIntValue(ProductEnum.ENABLE_SERIAL_NUMBER.getAttr());
            if (BasicConstant.ONE.equals(enableSerialNumber)) {
                enableSerialProductIds.add(productEntityExt.getId());
            }
        }

        // 删除出入库单，对应的流水记录一并删除
        productSerialFlowModel.deleteBatch(refIdIn, corpid, businessType, enableSerialProductIds);
        // 没有上游序列号的出入库单删除，流水记录以及结存记录del=1;否则序列号结存更新为上游单据的数据
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<ProductSerialBalanceEntity> balanceEntities;
        XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByCode(businessType);
        switch (xbbRefTypeEnum) {
            case PURCHASE_INSTOCK:
            case ORI_STOCK:
            case PRODUCTION_INSTOCK:
                deleteBatch(refIdIn, corpid, businessType, null);
                break;
            case RETURNED_PURCHASE:
            case RETURNED_PURCHASE_OUTSTOCK:
            case CONTRACT_OUTSTOCK:
            case REFUND:
            case REFUND_INSTOCK:
            case PRODUCTION_MATERIEL_OUTSTOCK:
            case RETURNED_MATERIEL_INSTOCK:
            case WORK_ORDER_OUTSTOCK:
            case OTHER_OUTSTOCK:
            case TRANSFER:
                param.put("corpid", corpid);
                param.put("refIdIn", refIdIn);
//                param.put("productIdIn", enableSerialProductIds);
                param.put("businessType", xbbRefTypeEnum.getCode());
                balanceEntities = productSerialBalanceModel.findEntitys(param);
                updateLastSerialFlow(balanceEntities, corpid);
                break;
            case OTHER_INSTOCK:
                param.put("corpid", corpid);
                param.put("ids", refIdIn);
                List<InstockEntityExt> instockEntityExts = instockModel.findEntitys(param);
                for (InstockEntityExt instockEntityExt : instockEntityExts) {
                    JSONObject instockEntityExtData = instockEntityExt.getData();
                    int type = instockEntityExtData.getIntValue(InstockEnum.TYPE.getAttr());
                    if (Objects.equals(InstockTypeEnum.OTHER_INSTOCK.getCode(), type) || Objects.equals(InstockTypeEnum.INVENTORY_INSTOCK.getCode(), type) || Objects.equals(type, InstockTypeEnum.ASSEMBLE_INSTOCK.getCode())) {
                        deleteByRefId(instockEntityExt.getId(), businessType, corpid);
                    } else if (Objects.equals(InstockTypeEnum.TRANSFER_INSTOCK.getCode(), type)) {
                        param.clear();
                        param.put("corpid", corpid);
                        param.put("refIdIn", refIdIn);
//                        param.put("productIdIn", enableSerialProductIds);
                        param.put("businessType", xbbRefTypeEnum.getCode());
                        balanceEntities = findEntitys(param);
                        updateLastSerialFlow(balanceEntities, corpid);
                    }
                }
                break;
            default:
                break;
        }
    }

    /**
     * 删除单据，序列号结存更新为最近时间的一条流水数据
     *
     * @param balanceEntities 删除单据的序列号结存记录
     * @param corpid          公司id
     * @throws XbbException 异常
     */
    private void updateLastSerialFlow(List<ProductSerialBalanceEntity> balanceEntities, String corpid) throws XbbException {
        for (ProductSerialBalanceEntity balanceEntity : balanceEntities) {
            String seqKey = balanceEntity.getSeqKey();
            // 序列号的最近一次流水记录
            ProductSerialFlowEntity lastSerialFlow = productSerialFlowModel.getLastSerialFlow(corpid, seqKey, balanceEntity.getRefId());
            if (Objects.nonNull(lastSerialFlow)) {
                ProductSerialBalanceEntity productSerialBalanceEntity = new ProductSerialBalanceEntity(lastSerialFlow);
                productSerialBalanceEntity.setId(balanceEntity.getId());
                productSerialBalanceModel.update(productSerialBalanceEntity);
            }
        }
    }

    @Override
    public Integer deleteBatch(List<Long> refIdIn, String corpid, Integer businessType, List<Long> enableSerialProductIds) {
        return productSerialBalanceDao.deleteBatch(refIdIn, corpid, businessType, enableSerialProductIds);
    }

    @Override
    public Integer deleteBatchByRefProductId(List<Long> refIdIn, String corpid, Integer businessType, List<Long> refProductIds) {
        if (CollectionUtils.isEmpty(refProductIds)) {
            return 0;
        }
        return productSerialBalanceDao.deleteBatchByRefProductId(refIdIn, corpid, businessType, refProductIds);
    }

    @Override
    public List<ProductSerialBalanceEntity> getByRefProductId(Long refProductId, int businessType, String corpid) {
        return productSerialBalanceDao.getByRefProductId(refProductId, businessType, corpid);
    }

    @Override
    public void deleteByRefId(Long refId, Integer businessType, String corpid) {
        productSerialBalanceDao.deleteByRefId(refId, businessType, corpid);
    }

    @Override
    public ProductSerialBalanceEntity getByKey(Long key, String corpid) {
        return productSerialBalanceDao.getByKey(key, corpid);
    }

    @Override
    public List<ProductSerialBalanceEntity> getBalanceByRefIdAndBusiness(List<Long> refIdIn, String corpid, Integer businessType) {
        return productSerialBalanceDao.getBalanceByRefIdAndBusiness(refIdIn, corpid, businessType);
    }

    @Override
    public List<ProductSerialBalanceEntity> getBySeqKeyList(List<String> seqKeyList, String corpid) {
        return productSerialBalanceDao.getBySeqKeyList(seqKeyList, corpid);
    }

    @Override
    public void updateBatchByParentId(String corpid, Long parentId, Integer visible) {
        productSerialBalanceDao.updateBatchByParentId(corpid, parentId, visible);
    }

}
